package com.andryu.opengl.java

import android.content.Context
import android.opengl.GLES30
import android.opengl.Matrix
import android.os.SystemClock
import com.andryu.base.LogUtils
import com.andryu.base.observer.OpenglJavaObserver
import com.andryu.opengl.utils.ShaderUtils
import dagger.hilt.android.qualifiers.ApplicationContext
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.ShortBuffer
import javax.inject.Inject


class GraphicCubeImpl @Inject constructor(@ApplicationContext private val context: Context) :
    OpenglJavaObserver {

    private var vertexBuffer: FloatBuffer
    private var colorBuffer: FloatBuffer
    private var drawListBuffer: ShortBuffer

    // 立方体的顶点
    private val cubeCoords = floatArrayOf(
        -0.5f, 0.5f, 0.5f,  // 前面
        -0.5f, -0.5f, 0.5f,
        0.5f, -0.5f, 0.5f,
        0.5f, 0.5f, 0.5f,

        -0.5f, 0.5f, -0.5f,  // 后面
        -0.5f, -0.5f, -0.5f,
        0.5f, -0.5f, -0.5f,
        0.5f, 0.5f, -0.5f ,
    )

    // 立方体的颜色
    private val colors = floatArrayOf(
        1.0f, 0.0f, 0.0f, 1.0f,  // 红色
        0.0f, 1.0f, 0.0f, 1.0f,  // 绿色
        0.0f, 0.0f, 1.0f, 1.0f,  // 蓝色
        1.0f, 1.0f, 0.0f, 1.0f,  // 黄色

        1.0f, 0.0f, 1.0f, 1.0f,  // 洋红
        0.0f, 1.0f, 1.0f, 1.0f,  // 青色
        1.0f, 0.5f, 0.0f, 1.0f,  // 橙色
        0.5f, 0.5f, 0.5f, 1.0f // 灰色
    )


    // 定义索引用于绘制六个面
    private val indices = shortArrayOf(
        0, 1, 2, 2, 3, 0, // 前面
        4, 5, 6, 6, 7, 4, // 后面
        0, 1, 5, 5, 4, 0, // 左面
        3, 2, 6, 6, 7, 3, // 右面
        0, 3, 7, 7, 4, 0, // 上面
        1, 2, 6, 6, 5, 1  // 下面
    )

    private var shaderProgram: Int = 0
    private val mvpMatrix = FloatArray(16)
    private val projectionMatrix = FloatArray(16)
    private val viewMatrix = FloatArray(16)
    private val rotationMatrix = FloatArray(16)

    init {
        vertexBuffer = ByteBuffer.allocateDirect(cubeCoords.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(cubeCoords)
        vertexBuffer.position(0)

        colorBuffer = ByteBuffer.allocateDirect(colors.size * 4)
            .order(ByteOrder.nativeOrder())
            .asFloatBuffer()
            .put(colors)
        colorBuffer.position(0)

        drawListBuffer = ByteBuffer.allocateDirect(indices.size * 2) // 每个short占2字节
            .order(ByteOrder.nativeOrder())
            .asShortBuffer()
            .put(indices)
        drawListBuffer.position(0)
    }

    override fun onSurfaceCreated() {
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
        GLES30.glClearDepthf(1.0f)

        GLES30.glEnable(GLES30.GL_DEPTH_TEST)
        GLES30.glDepthFunc(GLES30.GL_LEQUAL)

        shaderProgram = ShaderUtils.createProgram(
            context.assets,
            "shader/vertex/cube.glsl",
            "shader/fragment/cube.glsl"
        )
    }

    override fun onSurfaceChanged(width: Int, height: Int) {
        GLES30.glViewport(0, 0, width, height)

        // 计算新的投影矩阵
        val ratio = width.toFloat() / height
        Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)
    }

    override fun onDrawFrame() {
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)

        // 设置相机视图
        Matrix.setLookAtM(viewMatrix, 0, 3f, 0f, 0f, 0f, 0f, 0f, 0f, 1f, 0f)
        // 计算投影和视图变换
        Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, viewMatrix, 0)

        // 旋转立方体
        val time = SystemClock.uptimeMillis() % 4000L
        val angle = 0.090f * time.toInt()
        Matrix.setRotateM(rotationMatrix, 0, angle, 0.0f, 1.0f, 0.0f) // 绕Y轴旋转
        val rotationMatrixZ = FloatArray(16)
        Matrix.setRotateM(rotationMatrixZ, 0, angle * 0.5f, 0.0f, 0.0f, 1.0f) // 绕Z轴旋转

        // 将两个旋转矩阵相乘
        val tempRotationMatrix = FloatArray(16)
        Matrix.multiplyMM(tempRotationMatrix, 0, rotationMatrix, 0, rotationMatrixZ, 0)

        // 将旋转应用于mvp矩阵
        val scratch = FloatArray(16)
        Matrix.multiplyMM(scratch, 0, mvpMatrix, 0, tempRotationMatrix, 0)
        System.arraycopy(scratch, 0, mvpMatrix, 0, 16) // 更新mvpMatrix


        // 使用程序
        GLES30.glUseProgram(shaderProgram)

        // 获取顶点着色器的位置句柄
        val positionHandle = GLES30.glGetAttribLocation(shaderProgram, "vPosition")
        // 获取颜色句柄
        val colorHandle = GLES30.glGetAttribLocation(shaderProgram, "aColor")
        // 获取变换矩阵句柄
        val mvpMatrixHandle = GLES30.glGetUniformLocation(shaderProgram, "uMVPMatrix")
        LogUtils.d("GraphicCubeImpl shaderProgram = $shaderProgram , positionHandle = $positionHandle , colorHandle = $colorHandle , mvpMatrixHandle = $mvpMatrixHandle")

        // 启用顶点属性
        GLES30.glEnableVertexAttribArray(positionHandle)
        // 准备顶点数据
        GLES30.glVertexAttribPointer(
            positionHandle,
            3,
            GLES30.GL_FLOAT,
            false,
            3*4,
            vertexBuffer
        )


        // 启用颜色属性
        GLES30.glEnableVertexAttribArray(colorHandle)
        // 准备颜色数据
        GLES30.glVertexAttribPointer(colorHandle, 4, GLES30.GL_FLOAT, false, 4*4, colorBuffer)

        // 将变换矩阵传递给着色器
        GLES30.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mvpMatrix, 0)

        ShaderUtils.glCheckError("glDrawArrays before")
        // 绘制立方体
        //GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, cubeCoords.size/3)
        GLES30.glDrawElements(GLES30.GL_TRIANGLES, indices.size, GLES30.GL_UNSIGNED_SHORT, drawListBuffer)

        ShaderUtils.glCheckError("glDrawArrays after")

        // 禁用顶点属性
        GLES30.glDisableVertexAttribArray(positionHandle)
        GLES30.glDisableVertexAttribArray(colorHandle)
    }
}